package com.mxchip.livestar.repository

import android.content.*
import android.provider.ContactsContract
import android.text.TextUtils
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.mxchip.livestar.base.ContactPOJO
import com.mxchip.livestar.base.SingletonHolder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.*
import kotlin.Comparator
import kotlin.collections.ArrayList


class ContactRepository private constructor(context: Context) {

    companion object : SingletonHolder<ContactRepository, Context>(::ContactRepository)

    private val contentResolver: ContentResolver = context.contentResolver

    private val PHONE_BOOK_LABEL = "phonebook_label"

    private val _contactList: MutableLiveData<List<ContactPOJO>> by lazy {
        MutableLiveData<List<ContactPOJO>>(arrayListOf())
    }

    val all: LiveData<List<ContactPOJO>>
        get() = _contactList

    init {
        GlobalScope.launch(Dispatchers.Main) {
            val list = reloadAll()
            _contactList.value = list
        }
    }

    fun insert(name: String, number: String) {
        GlobalScope.launch(Dispatchers.Main) {
            batchInsert(name, number)
            val list = reloadAll()
            _contactList.value = list
        }
    }

    private suspend fun batchInsert(name: String, number: String) = withContext(Dispatchers.IO) {
        val ops = arrayListOf<ContentProviderOperation>()

        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValues(ContentValues())
                .build())

        //Add Name
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,0 )
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name)
                .build())


        //Add Phone Number
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,0 )
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, number)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
                .build())

        val result = contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)

        Log.e("ContactRepository", "result: ${Arrays.toString(result)}")
    }

    fun update(rawContactId: Long, name: String, number: String) {
        GlobalScope.launch(Dispatchers.Main) {
            batchUpdate(rawContactId, name, number)
            val list = reloadAll()
            _contactList.value = list
        }
    }

    private suspend fun batchUpdate(rawContactId: Long, name: String, number: String) = withContext(Dispatchers.IO) {

        Log.e("ContactRepository", "update id: $rawContactId, name: $name, number: $number")

        val ops = arrayListOf<ContentProviderOperation>()

        ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=?" + " AND " + ContactsContract.Data.MIMETYPE + "=?", arrayOf(rawContactId.toString(), ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE))
                .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name)
                .build())

        ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=?" + " AND " + ContactsContract.Data.MIMETYPE + " =?", arrayOf(rawContactId.toString(), ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE))
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, number)
                .build())

        val result = contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)

        Log.e("ContactRepository", "result: ${result.contentToString()}")
    }


    fun deleteById(rawContactId: Long) {
        GlobalScope.launch(Dispatchers.Main) {
            batchDeleteById(rawContactId)
            val list = reloadAll()
            _contactList.value = list
        }
    }

    private suspend fun batchDeleteById(rawContactId: Long) = withContext(Dispatchers.IO) {
        val ops = arrayListOf<ContentProviderOperation>()

        ops.add(ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI)
                .withSelection(ContactsContract.RawContacts._ID + "=?", arrayOf(rawContactId.toString()))
                .build())

        ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
                .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=?", arrayOf(rawContactId.toString()))
                .build())

        val result = contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)

        Log.e("ContactRepository", "result: ${result.contentToString()}")
    }
    
    private suspend fun reloadAll(): List<ContactPOJO> = withContext(Dispatchers.IO) {

        Log.e("ContactRepository ", "Thread.currentThread() reloadAll " + Thread.currentThread().name)

        val data: ArrayList<ContactPOJO> = arrayListOf()

        var contactName: String
        var data_table_id: Int
        var contactNumber: String
        var label: String
        var contactId: Long
        var photoId: Long
        val mapForMulti: MutableMap<String, String?> = HashMap()
        // 获取手机联系人
        val cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null)
                ?: return@withContext emptyList<ContactPOJO>()

        val data_table_id_index = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID)
        val contactIdIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)
        val displayNameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
        val phoneIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
        val photoIdIndex = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID)
        val labelIndex = cursor.getColumnIndex(PHONE_BOOK_LABEL)
        try {
            var sameContactIdPhoneCount = 0
            while (cursor.moveToNext()) {
                contactName = cursor.getString(displayNameIndex)
                data_table_id = cursor.getInt(data_table_id_index)
                contactId = cursor.getLong(contactIdIndex)
                contactNumber = cursor.getString(phoneIndex)
                if (contactNumber == null || contactNumber.isEmpty()) //过滤自身手机号和空号
                    continue
                sameContactIdPhoneCount = if (mapForMulti.containsKey(contactId.toString())) {
                    if (TextUtils.isEmpty(mapForMulti[contactId.toString()])) 1 else mapForMulti[contactId.toString()]!!.toInt() + 1
                } else 0
                if (sameContactIdPhoneCount >= 10) continue
                if (contactNumber.contains("-")) {
                    contactNumber = contactNumber.replace("-", "")
                }
                if (contactNumber.contains("/")) {
                    contactNumber = contactNumber.replace("/", "")
                }
                if (contactNumber.contains(" ")) {
                    contactNumber = contactNumber.replace(" ", "")
                }
                mapForMulti[contactId.toString()] = sameContactIdPhoneCount.toString()
                label = cursor.getString(labelIndex)
                val contacts = ContactPOJO()
                contacts.contactName = contactName
                contacts.contactNumber = contactNumber
                contacts.rawContactId = contactId
                // contacts.contract = data_table_id.toString()
                contacts.pys = label

                Log.e("ContactRepository", "contacts $contacts")
                data.add(contacts)
            }
        } catch (e: Exception) {
            // ContractsUtil.logger.info(" getContactContactsByPhone error" + e.message)
            e.printStackTrace()
        } finally {
            cursor.close()
        }

        val list = data.sortedWith(Comparator { l, r ->
            if (l == null || r == null) {
                return@Comparator 0
            }

            val lhsSortLetters: String? = l.pys?.substring(0, 1)?.toUpperCase()
            val rhsSortLetters: String? = r.pys?.substring(0, 1)?.toUpperCase()

            return@Comparator if (lhsSortLetters == null || rhsSortLetters == null) {
                0
            } else lhsSortLetters.compareTo(rhsSortLetters)
        })

        return@withContext list

        /*withContext(Dispatchers.Main) {

            Log.e("ContactRepository", "contactList.value: $list")

            contactList.value = list
        }*/

    }


}